package com.cs410.collabwriting.main;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Vector;

import com.cs410.collabwriting.tools.DatabaseManager;
import com.cs410.collabwriting.tools.queryTools.DatabaseTable;
import com.cs410.collabwriting.tools.queryTools.QueryBuilder;
import com.cs410.collabwriting.tools.queryTools.QueryCondition;
import com.cs410.collabwriting.tools.queryTools.QueryType;
import com.cs410.collabwriting.tools.queryTools.tables.COMMENT_TABLE;
import com.cs410.collabwriting.tools.queryTools.tables.POST_TABLE;
import com.cs410.collabwriting.tools.queryTools.tables.STORY_TABLE;
import com.cs410.collabwriting.tools.queryTools.tables.UPVOTE_TABLE;


public class Story implements DatabaseObjects {
	
	private int m_storyID = -1;
	private String m_authorID = null;
	private Prompt m_storyPrompt = null;
	private String m_title = null;
	
	//Info to add:
	private String m_dateCreated = null; 
	
	private HashMap<Integer, Comment> m_allComments = null; //<CommentID, CommentsObject>
	private HashMap<Integer, Post> m_allPosts = null; //<PostID, PostObject>
	
	public Story (String creatorID, int newStoryID, Prompt promptForStory){ //called by createStory method in StoryManager
		
		m_authorID = creatorID;
		m_storyID = newStoryID;
		
		m_allComments = new HashMap<Integer, Comment>();
		m_allPosts = new HashMap<Integer, Post>();
		
		if (promptForStory!=null) m_storyPrompt = promptForStory;
	}
	
	@Override
	public void update() {
		// set all vars except storyid to null -- don't know if I need to do this?
		
	}

	//Retrieve story ID
	public int getStoryID(){
		return m_storyID;
	}
	
	//Get the ID of the author of the story
	public String getAuthorID(){
		return m_authorID;
	}
		
		
	//Gets the story prompt, if there is one; null if there isn't
	public Prompt getPrompt(){
		return m_storyPrompt;
	}
	
	// Returns the date and time when the story was created
	public String getCreatedTimestamp() {
		if (m_dateCreated == null){
			
			m_dateCreated = DatabaseManager.executeExactQuery(
				new QueryBuilder(QueryType.SELECTION)
				.addColumns(STORY_TABLE.TIMESTAMP)
				.addTables(DatabaseTable.STORY_TABLE)
				.addConditions(QueryCondition.AND, STORY_TABLE.STORYID, QueryCondition.EQ, String.valueOf(m_storyID) )
				.value() );				
		}

        SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");
        SimpleDateFormat formatter = new SimpleDateFormat("MMM dd, yyyy HH:mm:ss");
        
        try {
            Date date = parser.parse(m_dateCreated);
            return formatter.format(date);
        } catch (ParseException e) {            
            return m_dateCreated.substring(0, m_dateCreated.length()-2);
        }       
	}
	
	public String getCreatedTimestampNum() {
		if (m_dateCreated == null){
			
			m_dateCreated = DatabaseManager.executeExactQuery(
				new QueryBuilder(QueryType.SELECTION)
				.addColumns(STORY_TABLE.TIMESTAMP)
				.addTables(DatabaseTable.STORY_TABLE)
				.addConditions(QueryCondition.AND, STORY_TABLE.STORYID, QueryCondition.EQ, String.valueOf(m_storyID) )
				.value() );				
		}

        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddkkmmss.S");
        try {
        	 Date date = formatter.parse(m_dateCreated);
             return date.toString();
   
        } catch (ParseException e) {            
            return m_dateCreated.substring(0, m_dateCreated.length()-2);
        }       
	}
	
	// Get the story title
	public String getTitle() {
		
		if (m_title == null){
		
			m_title = DatabaseManager.executeExactQuery(
				new QueryBuilder(QueryType.SELECTION)
				.addColumns(STORY_TABLE.STORYTITLE)
				.addTables(DatabaseTable.STORY_TABLE)
				.addConditions(QueryCondition.AND, STORY_TABLE.STORYID, QueryCondition.EQ, String.valueOf(m_storyID) )
				.value() );				
		}
		return m_title;
	}
	
	
	//Get the view count of story
	public int getViewCount() {
		String currViewCountString = DatabaseManager.executeExactQuery(
			new QueryBuilder(QueryType.SELECTION)
			.addColumns(STORY_TABLE.VIEWCOUNT)
			.addTables(DatabaseTable.STORY_TABLE)
			.addConditions(QueryCondition.AND, STORY_TABLE.STORYID, QueryCondition.EQ, m_storyID )
			.value() );	
		int currViewCount = Integer.valueOf(currViewCountString);
			
		return currViewCount;
	}
	
	//Increment view count of story in DB
	public boolean incrementViewCount() {
		
		int newViewCount = this.getViewCount() + 1;
		
		int viewCountUpdated = DatabaseManager.executeUpdate(
			new QueryBuilder(QueryType.UPDATE)
			.addColumns(STORY_TABLE.VIEWCOUNT)
			.addTables(DatabaseTable.STORY_TABLE)
			.addValues(String.valueOf(newViewCount))
			.addConditions(QueryCondition.AND, STORY_TABLE.STORYID, QueryCondition.EQ, m_storyID )
			.value() );	
			
		if (viewCountUpdated == 1) return true;
		else return false;
	}
	
	//Get the number of votes for the story
	public int getVoteCount() {
		
		int voteCount = 0;
		
		String numVotes = DatabaseManager.executeExactQuery(
			new QueryBuilder(QueryType.SELECTION)
			.addColumns("COUNT(*)") 
			.addTables(DatabaseTable.UPVOTE_TABLE)
			.addConditions(QueryCondition.AND, UPVOTE_TABLE.STORYID, QueryCondition.EQ, String.valueOf(m_storyID) )
			.value() );	
					
		voteCount = Integer.valueOf(numVotes);
		return voteCount;
	}
			
	public boolean userVoted( String voterID ) {
		String votedBefore = DatabaseManager.executeExactQuery(
				new QueryBuilder(QueryType.SELECTION)
				.addColumns("COUNT(*)")
				.addTables(DatabaseTable.UPVOTE_TABLE)
				.addConditions(QueryCondition.AND, UPVOTE_TABLE.USERID, QueryCondition.EQ, String.valueOf(voterID))
				.addConditions(QueryCondition.AND, UPVOTE_TABLE.STORYID, QueryCondition.EQ, String.valueOf(m_storyID))
				.value() );
		if( votedBefore != null && Integer.parseInt( votedBefore ) > 0 ) {
			return true;
		}
		return false;
	}

	//Vote for this story
	public boolean upvoteStory(String voterID){
		
		boolean votedUpFlag = false;
		
		//Check if user has voted for this story previously
		String votedBefore = DatabaseManager.executeExactQuery(
				new QueryBuilder(QueryType.SELECTION)
				.addColumns("COUNT(*)")
				.addTables(DatabaseTable.UPVOTE_TABLE)
				.addConditions(QueryCondition.AND, UPVOTE_TABLE.USERID, QueryCondition.EQ, String.valueOf(voterID))
				.addConditions(QueryCondition.AND, UPVOTE_TABLE.STORYID, QueryCondition.EQ, String.valueOf(m_storyID))
				.value() );
		
		if (Integer.valueOf(votedBefore) == 0 ) { //If they have not voted before, add their vote
			int voted = DatabaseManager.executeUpdate(
				new QueryBuilder(QueryType.INSERT)
				.addColumns(UPVOTE_TABLE.USERID, UPVOTE_TABLE.STORYID )
				.addTables(DatabaseTable.UPVOTE_TABLE)
				.addValues( QueryBuilder.toSQLChar(voterID), String.valueOf(m_storyID) )
				.value() );		
			
			if (voted == 1) votedUpFlag = true;
		}
		return votedUpFlag;
	}
		
	// Add a comment for this story
	public boolean comment(String commenterID, String comment) {
		
		boolean commentAddedFlag = false;
		
		int commentAdded = DatabaseManager.executeUpdate(
			new QueryBuilder(QueryType.INSERT)
			.addColumns(COMMENT_TABLE.STORYID, COMMENT_TABLE.USERID, COMMENT_TABLE.COMMENT)
			.addTables(DatabaseTable.COMMENT_TABLE)
			.addValues( String.valueOf(m_storyID), QueryBuilder.toSQLChar(commenterID), QueryBuilder.toSQLChar(comment))
			.value() );	
		
		String commentID = DatabaseManager.executeExactQuery(
			new QueryBuilder(QueryType.SELECTION)
			.addColumns(COMMENT_TABLE.COMMENTID)
			.addTables(DatabaseTable.COMMENT_TABLE)
			.addConditions(QueryCondition.AND, COMMENT_TABLE.STORYID, QueryCondition.EQ, String.valueOf(m_storyID) )
			.addConditions(QueryCondition.AND, COMMENT_TABLE.USERID, QueryCondition.EQ, String.valueOf(commenterID) )
			.addConditions(QueryCondition.AND, COMMENT_TABLE.COMMENT, QueryCondition.EQ, String.valueOf(comment) )
			.value() );		
	
			Comment commentObject = new Comment(Integer.valueOf(commentID));
			m_allComments.put(Integer.valueOf(Integer.valueOf(commentID)), commentObject); //Put into hashmap of comments
			
		if (commentAdded == 1) commentAddedFlag = true;
		
		return commentAddedFlag;
	}
	
	
	// Returns the comment object with storyID
	public Comment getCommentByID(int commentID) {
		Comment commentToGet = m_allComments.get(commentID);
				
		if (commentToGet==null){ //Need to grab from DB & create appropriate comment object for it
			commentToGet = new Comment(commentID);
			m_allComments.put(commentID, commentToGet);
		}		
		
		return commentToGet;
	}
	
	// Returns all the comments for the story sorted by ascending time (most recent comment at end
	// of array list)
	public ArrayList<Comment> getAllComments(){
		
		ArrayList<String[]> allCommentIDsList = DatabaseManager.executeQueryWithColumnNames(
				new QueryBuilder(QueryType.SELECTION)
				.addColumns(COMMENT_TABLE.COMMENTID)
				.addTables(DatabaseTable.COMMENT_TABLE)
				.addConditions(QueryCondition.AND, COMMENT_TABLE.STORYID, QueryCondition.EQ, String.valueOf(m_storyID) )
				.addAdditionalCriteria("ORDER BY timestamp ASC")
				.value() );	
		
		ArrayList<Comment> commentsSortedByTime = new ArrayList<Comment>();
		
		for (int i= 1; i < allCommentIDsList.size(); i++){
			int IDcomment = Integer.valueOf(allCommentIDsList.get(i)[0]);
			Comment comment = this.getCommentByID(IDcomment); //this will add comment to hashmap if not already there
			commentsSortedByTime.add(comment);
		}
		
		return commentsSortedByTime;	
	}
	
	
	// Return all comments for the story as a hash map
	public HashMap<Integer, Comment> getCommentsHashMap(){
		
		ArrayList<String[]> allCommentIDsList = DatabaseManager.executeQueryWithColumnNames(
				new QueryBuilder(QueryType.SELECTION)
				.addColumns(COMMENT_TABLE.COMMENTID)
				.addTables(DatabaseTable.COMMENT_TABLE)
				.addConditions(QueryCondition.AND, COMMENT_TABLE.STORYID, QueryCondition.EQ, String.valueOf(m_storyID) )
				.value() );	
		
		for (int i= 1; i < allCommentIDsList.size(); i++){
			int IDcomment = Integer.valueOf(allCommentIDsList.get(i)[0]);
			Comment comment = this.getCommentByID(IDcomment); //this will add comment to hashmap if not already there
		}
		
		return m_allComments;		
	}
	
	// Add a post for this story
	public boolean contributePost(String posterID, String postContent){
		
		boolean postAddedFlag = false;
//		postContent.replaceAll(".", "&#46;");
		
		int postAdded = DatabaseManager.executeUpdate(
			new QueryBuilder(QueryType.INSERT)
			.addColumns(POST_TABLE.STORYID, POST_TABLE.USERID, POST_TABLE.POST)
			.addTables(DatabaseTable.POST_TABLE)
			.addValues( String.valueOf(m_storyID), QueryBuilder.toSQLChar(posterID), QueryBuilder.toSQLChar(postContent))
			.value() );	
		
		String postID = DatabaseManager.executeExactQuery(
				new QueryBuilder(QueryType.SELECTION)
				.addColumns(POST_TABLE.POSTID)
				.addTables(DatabaseTable.POST_TABLE)
				.addConditions(QueryCondition.AND, POST_TABLE.STORYID, QueryCondition.EQ, m_storyID)
				.addConditions(QueryCondition.AND, POST_TABLE.USERID, QueryCondition.EQ, posterID )
				.addConditions(QueryCondition.AND, POST_TABLE.POST, QueryCondition.EQ, postContent)
				.value() );		
		
		Post newPost = new Post(Integer.valueOf(postID)); 
		m_allPosts.put(Integer.valueOf(Integer.valueOf(postID)), newPost); //Put into hashmap of posts
		
		if (postAdded == 1) postAddedFlag = true;
	
		return postAddedFlag;
	}
	
	
	// Returns the post object with storyID
	public Post getPostByID(int postID){
		Post postToGet = m_allPosts.get(postID);
		
		if (postToGet==null){ //Need to grab from DB & create appropriate post object for it
			postToGet = new Post(postID);
			m_allPosts.put(postID, postToGet);
		}		
		return postToGet;
	}
	
	
	// Return all posts for the story with the oldest post at the beginning of
	//the array list and the most recent at the end
	public ArrayList<Post> getAllPosts(){
				
		ArrayList<String[]> allPostIDsList = DatabaseManager.executeQueryWithColumnNames(
				new QueryBuilder(QueryType.SELECTION)
				.addColumns(POST_TABLE.POSTID)
				.addTables(DatabaseTable.POST_TABLE)
				.addConditions(QueryCondition.AND, COMMENT_TABLE.STORYID, QueryCondition.EQ, m_storyID )
				.addAdditionalCriteria("ORDER BY timestamp ASC")
				.value() );	
		
		ArrayList<Post> postsSortedByTime = new ArrayList<Post>();
		
		for (int i= 1; i < allPostIDsList.size(); i++){
			int IDpost = Integer.valueOf(allPostIDsList.get(i)[0]);
			Post post = this.getPostByID(IDpost); //this will add comment to hashmap if not already there
			postsSortedByTime.add(post);
		}
		
		return postsSortedByTime;
	}
	
	// Return all tags for this story with their tag frequency as a hashmap
	public HashMap<String, Integer> getAllTags(){
		
		HashMap<String, Integer> tagFrequencies = new HashMap<String, Integer>();
		TagManager tagMger = TagManager.getInstance();
		String[] tagConstants = TagConstant.getAllTagNames();
		
		for (int i=0; i < tagConstants.length; i++){
			int tagCount = tagMger.getStoryTagCount(m_storyID, tagConstants[i]);
			tagFrequencies.put(tagConstants[i], tagCount);
		}
		
		return tagFrequencies;
	}	
		
}
